package view;

import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.rmi.Naming;
import java.rmi.RemoteException;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import model.Order;
import server.Server;
import view.dialog.StartupDialog;
import client.Client;
import client.ClientImpl;

public class ClientGUI extends JFrame {
	private static final long serialVersionUID = 7247037600102370073L;
	
	public static final String SERVER_ADDRESS = "rmi://localhost:12345/ServerImpl";
	
	private static final int TAB_BUY = 0;
	private static final int TAB_SELL = 1;
	private static final int TAB_USER_ORDERS = 2;
	
	public Server server;
	private Client client;
	
	// place holder for all the tab panels
	private JTabbedPane tabs;
	
	// essentially the tabs we current have
	private BuyPanel buyPanel;
	private SellPanel sellPanel;
	private UserOrderPanel userOrderPanel;
	private HistoryPanel historyPanel;
	
	public static void main(String[] args) throws IOException {
		new ClientGUI();
	}
	
	public ClientGUI() {
		super("Stock Market Client");
		try {
			// create a server remote object reference
			server = (Server) Naming.lookup(SERVER_ADDRESS);
			// create a client object
			client = new ClientImpl(this);
		} catch (Exception e) {
			JOptionPane.showMessageDialog(this, e.getMessage(),
					"Error", JOptionPane.ERROR_MESSAGE);
			System.exit(1);
		}
		setLayout(new BorderLayout());
		setSize(600, 400);
		
		// create the tabs/tab holder
		tabs = new JTabbedPane();
		
		buyPanel = new BuyPanel();
		sellPanel = new SellPanel();
		userOrderPanel = new UserOrderPanel();
		historyPanel = new HistoryPanel();
		
		tabs.addTab("Buy", buyPanel);
		tabs.addTab("Sell", sellPanel);
		tabs.addTab("My Orders", userOrderPanel);
		tabs.addTab("History", historyPanel);
		tabs.setEnabled(false);
		
		// when we change tabs, make sure to update our data
		tabs.addChangeListener(new ChangeListener() {
			
			public void stateChanged(ChangeEvent arg0) {
				try {
					switch (tabs.getSelectedIndex()) {
					case TAB_BUY:
						buyPanel.populate(server, client);
						break;
					case TAB_SELL:
						sellPanel.populate(server, client);
						break;
					case TAB_USER_ORDERS:
						userOrderPanel.populate(server, client);
						break;
					}
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		});
		add(tabs);
		
		setDefaultCloseOperation(EXIT_ON_CLOSE);
		addWindowListener(new ExitListener());
		
		// centre it
		setLocationRelativeTo(null);
		setVisible(true);
		// procede to the login/registration
		startup();
	}
	
	/**
	 * Show the registration/login dialog 
	 */
	private void startup() {
		try {
			buyPanel.getBuyButton().setEnabled(false);
			new StartupDialog(ClientGUI.this).setAlwaysOnTop(true);
		} catch (Exception e) {
			System.err.println("couldn't connect to server, error connecting");
			return;
		}
	}

	/**
	 * If logged in, initialize gui components with data from server 
	 * @throws RemoteException
	 */
	public void populate() throws RemoteException {
		tabs.setEnabled(true);
		buyPanel.populate(server, client);
		sellPanel.populate(server, client);
		historyPanel.setup(server, client);
	}
	
	/**
	 * Visually notify client of order completion.
	 * @param o 
	 * 		Details of order bought.
	 * @throws RemoteException
	 */
	public void alertPurchase(final Order o) throws RemoteException {
		/* swing is not thread safe, this method is an rmi callback and must be treated as it's own thread,
		  so we use this swing utility to cope */ 
		SwingUtilities.invokeLater(new Runnable() {
			
			public void run() {
				JOptionPane.showMessageDialog(ClientGUI.this, "Bought "
						+ o.getNumber() + " of " + o.getStockName() + " at "
						+ o.getPrice(), "Bought",
						JOptionPane.INFORMATION_MESSAGE);

			}
		});
	}

	/**
	 * Visually notify client of order completion.
	 * @param o 
	 * 		Details of order sold.
	 * @throws RemoteException
	 */
	public void alertSold(final Order o) throws RemoteException {
		/* swing is not thread safe, this method is an rmi callback and must be treated as it's own thread,
		  so we use this swing utility to cope */
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				JOptionPane.showMessageDialog(ClientGUI.this,  "Sold "
						+ o.getNumber() + " of " + o.getStockName() + " at "
						+ o.getPrice(), "Sold", 
						JOptionPane.INFORMATION_MESSAGE);

			}
		});
	}
	
	/** Send a logout request to the server on window close */
	class ExitListener extends WindowAdapter {
		public void windowClosing(WindowEvent e) {
			try {
				if(server != null && client != null && client.getUser() != null) {
					server.logoutUser(client);
				}
				System.err.println("logout done");
			} catch (RemoteException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}
	}
	
	/**
	 * Gets the server object
	 * @return Server
	 * 		The server object reference
	 */
	public Server getServer() {
		return server;
	}
	
	/**
	 * Gets the client object
	 * @return
	 * 		The client object reference
	 */
	public Client getClient() {
		return client;
	}
	
	/**
	 * Gets the buyPanel object
	 * @return JPanel
	 * 		The buyPanel object
	 */
	public BuyPanel getBuyPanel() {
		return buyPanel;
	}

}
